<!DOCTYPE html><html><head><meta charset="utf-8"><style>body {
  max-width: 980px;
  border: 1px solid #ddd;
  outline: 1300px solid #fff;
  margin: 16px auto;
}

body .markdown-body
{
  padding: 45px;
}

@font-face {
  font-family: fontawesome-mini;
  src: url(data:font/woff;charset=utf-8;base64,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) format('woff');
}

.markdown-body {
  font-family: sans-serif;
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
  color: #333333;
  overflow: hidden;
  font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;
  font-size: 16px;
  line-height: 1.6;
  word-wrap: break-word;
}

.markdown-body a {
  background: transparent;
}

.markdown-body a:active,
.markdown-body a:hover {
  outline: 0;
}

.markdown-body b,
.markdown-body strong {
  font-weight: bold;
}

.markdown-body mark {
  background: #ff0;
  color: #000;
  font-style: italic;
  font-weight: bold;
}

.markdown-body sub,
.markdown-body sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}
.markdown-body sup {
  top: -0.5em;
}
.markdown-body sub {
  bottom: -0.25em;
}

.markdown-body h1 {
  font-size: 2em;
  margin: 0.67em 0;
}

.markdown-body img {
  border: 0;
}

.markdown-body hr {
  -moz-box-sizing: content-box;
  box-sizing: content-box;
  height: 0;
}

.markdown-body pre {
  overflow: auto;
}

.markdown-body code,
.markdown-body kbd,
.markdown-body pre,
.markdown-body samp {
  font-family: monospace, monospace;
  font-size: 1em;
}

.markdown-body input {
  color: inherit;
  font: inherit;
  margin: 0;
}

.markdown-body html input[disabled] {
  cursor: default;
}

.markdown-body input {
  line-height: normal;
}

.markdown-body input[type="checkbox"] {
  box-sizing: border-box;
  padding: 0;
}

.markdown-body table {
  border-collapse: collapse;
  border-spacing: 0;
}

.markdown-body td,
.markdown-body th {
  padding: 0;
}

.markdown-body .codehilitetable {
  border: 0;
  border-spacing: 0;
}

.markdown-body .codehilitetable tr {
  border: 0;
}

.markdown-body .codehilitetable pre,
.markdown-body .codehilitetable div.codehilite {
  margin: 0;
}

.markdown-body .linenos,
.markdown-body .code,
.markdown-body .codehilitetable td {
  border: 0;
  padding: 0;
}

.markdown-body td:not(.linenos) .linenodiv {
  padding: 0 !important;
}

.markdown-body .code {
  width: 100%;
}

.markdown-body .linenos div pre,
.markdown-body .linenodiv pre,
.markdown-body .linenodiv {
  border: 0;
  -webkit-border-radius: 0;
  -moz-border-radius: 0;
  border-radius: 0;
  -webkit-border-top-left-radius: 3px;
  -webkit-border-bottom-left-radius: 3px;
  -moz-border-radius-topleft: 3px;
  -moz-border-radius-bottomleft: 3px;
  border-top-left-radius: 3px;
  border-bottom-left-radius: 3px;
}

.markdown-body .code div pre,
.markdown-body .code div {
  border: 0;
  -webkit-border-radius: 0;
  -moz-border-radius: 0;
  border-radius: 0;
  -webkit-border-top-right-radius: 3px;
  -webkit-border-bottom-right-radius: 3px;
  -moz-border-radius-topright: 3px;
  -moz-border-radius-bottomright: 3px;
  border-top-right-radius: 3px;
  border-bottom-right-radius: 3px;
}

.markdown-body * {
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

.markdown-body input {
  font: 13px Helvetica, arial, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol";
  line-height: 1.4;
}

.markdown-body a {
  color: #4183c4;
  text-decoration: none;
}

.markdown-body a:hover,
.markdown-body a:focus,
.markdown-body a:active {
  text-decoration: underline;
}

.markdown-body hr {
  height: 0;
  margin: 15px 0;
  overflow: hidden;
  background: transparent;
  border: 0;
  border-bottom: 1px solid #ddd;
}

.markdown-body hr:before,
.markdown-body hr:after {
  display: table;
  content: " ";
}

.markdown-body hr:after {
  clear: both;
}

.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
  margin-top: 15px;
  margin-bottom: 15px;
  line-height: 1.1;
}

.markdown-body h1 {
  font-size: 30px;
}

.markdown-body h2 {
  font-size: 21px;
}

.markdown-body h3 {
  font-size: 16px;
}

.markdown-body h4 {
  font-size: 14px;
}

.markdown-body h5 {
  font-size: 12px;
}

.markdown-body h6 {
  font-size: 11px;
}

.markdown-body blockquote {
  margin: 0;
}

.markdown-body ul,
.markdown-body ol {
  padding: 0;
  margin-top: 0;
  margin-bottom: 0;
}

.markdown-body ol ol,
.markdown-body ul ol {
  list-style-type: lower-roman;
}

.markdown-body ul ul ol,
.markdown-body ul ol ol,
.markdown-body ol ul ol,
.markdown-body ol ol ol {
  list-style-type: lower-alpha;
}

.markdown-body dd {
  margin-left: 0;
}

.markdown-body code,
.markdown-body pre,
.markdown-body samp {
  font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
  font-size: 12px;
}

.markdown-body pre {
  margin-top: 0;
  margin-bottom: 0;
}

.markdown-body kbd {
  background-color: #e7e7e7;
  background-image: -moz-linear-gradient(#fefefe, #e7e7e7);
  background-image: -webkit-linear-gradient(#fefefe, #e7e7e7);
  background-image: linear-gradient(#fefefe, #e7e7e7);
  background-repeat: repeat-x;
  border-radius: 2px;
  border: 1px solid #cfcfcf;
  color: #000;
  padding: 3px 5px;
  line-height: 10px;
  font: 11px Consolas, "Liberation Mono", Menlo, Courier, monospace;
  display: inline-block;
}

.markdown-body>*:first-child {
  margin-top: 0 !important;
}

.markdown-body>*:last-child {
  margin-bottom: 0 !important;
}

.markdown-body .headerlink {
  font: normal 400 16px fontawesome-mini;
  vertical-align: middle;
  margin-left: -16px;
  float: left;
  display: inline-block;
  text-decoration: none;
  opacity: 0;
  color: #333;
}

.markdown-body .headerlink:focus {
  outline: none;
}

.markdown-body h1 .headerlink {
  margin-top: 0.8rem;
}

.markdown-body h2 .headerlink,
.markdown-body h3 .headerlink {
  margin-top: 0.6rem;
}

.markdown-body h4 .headerlink {
  margin-top: 0.2rem;
}

.markdown-body h5 .headerlink,
.markdown-body h6 .headerlink {
  margin-top: 0;
}

.markdown-body .headerlink:hover,
.markdown-body h1:hover .headerlink,
.markdown-body h2:hover .headerlink,
.markdown-body h3:hover .headerlink,
.markdown-body h4:hover .headerlink,
.markdown-body h5:hover .headerlink,
.markdown-body h6:hover .headerlink {
  opacity: 1;
  text-decoration: none;
}

.markdown-body h1 {
  padding-bottom: 0.3em;
  font-size: 2.25em;
  line-height: 1.2;
  border-bottom: 1px solid #eee;
}

.markdown-body h2 {
  padding-bottom: 0.3em;
  font-size: 1.75em;
  line-height: 1.225;
  border-bottom: 1px solid #eee;
}

.markdown-body h3 {
  font-size: 1.5em;
  line-height: 1.43;
}

.markdown-body h4 {
  font-size: 1.25em;
}

.markdown-body h5 {
  font-size: 1em;
}

.markdown-body h6 {
  font-size: 1em;
  color: #777;
}

.markdown-body p,
.markdown-body blockquote,
.markdown-body ul,
.markdown-body ol,
.markdown-body dl,
.markdown-body table,
.markdown-body pre,
.markdown-body .admonition {
  margin-top: 0;
  margin-bottom: 16px;
}

.markdown-body hr {
  height: 4px;
  padding: 0;
  margin: 16px 0;
  background-color: #e7e7e7;
  border: 0 none;
}

.markdown-body ul,
.markdown-body ol {
  padding-left: 2em;
}

.markdown-body ul ul,
.markdown-body ul ol,
.markdown-body ol ol,
.markdown-body ol ul {
  margin-top: 0;
  margin-bottom: 0;
}

.markdown-body li>p {
  margin-top: 16px;
}

.markdown-body dl {
  padding: 0;
}

.markdown-body dl dt {
  padding: 0;
  margin-top: 16px;
  font-size: 1em;
  font-style: italic;
  font-weight: bold;
}

.markdown-body dl dd {
  padding: 0 16px;
  margin-bottom: 16px;
}

.markdown-body blockquote {
  padding: 0 15px;
  color: #777;
  border-left: 4px solid #ddd;
}

.markdown-body blockquote>:first-child {
  margin-top: 0;
}

.markdown-body blockquote>:last-child {
  margin-bottom: 0;
}

.markdown-body table {
  display: block;
  width: 100%;
  overflow: auto;
  word-break: normal;
  word-break: keep-all;
}

.markdown-body table th {
  font-weight: bold;
}

.markdown-body table th,
.markdown-body table td {
  padding: 6px 13px;
  border: 1px solid #ddd;
}

.markdown-body table tr {
  background-color: #fff;
  border-top: 1px solid #ccc;
}

.markdown-body table tr:nth-child(2n) {
  background-color: #f8f8f8;
}

.markdown-body img {
  max-width: 100%;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

.markdown-body code,
.markdown-body samp {
  padding: 0;
  padding-top: 0.2em;
  padding-bottom: 0.2em;
  margin: 0;
  font-size: 85%;
  background-color: rgba(0,0,0,0.04);
  border-radius: 3px;
}

.markdown-body code:before,
.markdown-body code:after {
  letter-spacing: -0.2em;
  content: "\00a0";
}

.markdown-body pre>code {
  padding: 0;
  margin: 0;
  font-size: 100%;
  word-break: normal;
  white-space: pre;
  background: transparent;
  border: 0;
}

.markdown-body .codehilite {
  margin-bottom: 16px;
}

.markdown-body .codehilite pre,
.markdown-body pre {
  padding: 16px;
  overflow: auto;
  font-size: 85%;
  line-height: 1.45;
  background-color: #f7f7f7;
  border-radius: 3px;
}

.markdown-body .codehilite pre {
  margin-bottom: 0;
  word-break: normal;
}

.markdown-body pre {
  word-wrap: normal;
}

.markdown-body pre code {
  display: inline;
  max-width: initial;
  padding: 0;
  margin: 0;
  overflow: initial;
  line-height: inherit;
  word-wrap: normal;
  background-color: transparent;
  border: 0;
}

.markdown-body pre code:before,
.markdown-body pre code:after {
  content: normal;
}

/* Admonition */
.markdown-body .admonition {
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  position: relative;
  border-radius: 3px;
  border: 1px solid #e0e0e0;
  border-left: 6px solid #333;
  padding: 10px 10px 10px 30px;
}

.markdown-body .admonition table {
  color: #333;
}

.markdown-body .admonition p {
  padding: 0;
}

.markdown-body .admonition-title {
  font-weight: bold;
  margin: 0;
}

.markdown-body .admonition>.admonition-title {
  color: #333;
}

.markdown-body .attention>.admonition-title {
  color: #a6d796;
}

.markdown-body .caution>.admonition-title {
  color: #d7a796;
}

.markdown-body .hint>.admonition-title {
  color: #96c6d7;
}

.markdown-body .danger>.admonition-title {
  color: #c25f77;
}

.markdown-body .question>.admonition-title {
  color: #96a6d7;
}

.markdown-body .note>.admonition-title {
  color: #d7c896;
}

.markdown-body .admonition:before,
.markdown-body .attention:before,
.markdown-body .caution:before,
.markdown-body .hint:before,
.markdown-body .danger:before,
.markdown-body .question:before,
.markdown-body .note:before {
  font: normal normal 16px fontawesome-mini;
  -moz-osx-font-smoothing: grayscale;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
  line-height: 1.5;
  color: #333;
  position: absolute;
  left: 0;
  top: 0;
  padding-top: 10px;
  padding-left: 10px;
}

.markdown-body .admonition:before {
  content: "\f056\00a0";
  color: 333;
}

.markdown-body .attention:before {
  content: "\f058\00a0";
  color: #a6d796;
}

.markdown-body .caution:before {
  content: "\f06a\00a0";
  color: #d7a796;
}

.markdown-body .hint:before {
  content: "\f05a\00a0";
  color: #96c6d7;
}

.markdown-body .danger:before {
  content: "\f057\00a0";
  color: #c25f77;
}

.markdown-body .question:before {
  content: "\f059\00a0";
  color: #96a6d7;
}

.markdown-body .note:before {
  content: "\f040\00a0";
  color: #d7c896;
}

.markdown-body .admonition::after {
  content: normal;
}

.markdown-body .attention {
  border-left: 6px solid #a6d796;
}

.markdown-body .caution {
  border-left: 6px solid #d7a796;
}

.markdown-body .hint {
  border-left: 6px solid #96c6d7;
}

.markdown-body .danger {
  border-left: 6px solid #c25f77;
}

.markdown-body .question {
  border-left: 6px solid #96a6d7;
}

.markdown-body .note {
  border-left: 6px solid #d7c896;
}

.markdown-body .admonition>*:first-child {
  margin-top: 0 !important;
}

.markdown-body .admonition>*:last-child {
  margin-bottom: 0 !important;
}

/* progress bar*/
.markdown-body .progress {
  display: block;
  width: 300px;
  margin: 10px 0;
  height: 24px;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px;
  background-color: #ededed;
  position: relative;
  box-shadow: inset -1px 1px 3px rgba(0, 0, 0, .1);
}

.markdown-body .progress-label {
  position: absolute;
  text-align: center;
  font-weight: bold;
  width: 100%; margin: 0;
  line-height: 24px;
  color: #333;
  text-shadow: 1px 1px 0 #fefefe, -1px -1px 0 #fefefe, -1px 1px 0 #fefefe, 1px -1px 0 #fefefe, 0 1px 0 #fefefe, 0 -1px 0 #fefefe, 1px 0 0 #fefefe, -1px 0 0 #fefefe, 1px 1px 2px #000;
  -webkit-font-smoothing: antialiased !important;
  white-space: nowrap;
  overflow: hidden;
}

.markdown-body .progress-bar {
  height: 24px;
  float: left;
  -webkit-border-radius: 3px;
  -moz-border-radius: 3px;
  border-radius: 3px;
  background-color: #96c6d7;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), inset 0 -1px 0 rgba(0, 0, 0, .1);
  background-size: 30px 30px;
  background-image: -webkit-linear-gradient(
    135deg, rgba(255, 255, 255, .4) 27%,
    transparent 27%,
    transparent 52%, rgba(255, 255, 255, .4) 52%,
    rgba(255, 255, 255, .4) 77%,
    transparent 77%, transparent
  );
  background-image: -moz-linear-gradient(
    135deg,
    rgba(255, 255, 255, .4) 27%, transparent 27%,
    transparent 52%, rgba(255, 255, 255, .4) 52%,
    rgba(255, 255, 255, .4) 77%, transparent 77%,
    transparent
  );
  background-image: -ms-linear-gradient(
    135deg,
    rgba(255, 255, 255, .4) 27%, transparent 27%,
    transparent 52%, rgba(255, 255, 255, .4) 52%,
    rgba(255, 255, 255, .4) 77%, transparent 77%,
    transparent
  );
  background-image: -o-linear-gradient(
    135deg,
    rgba(255, 255, 255, .4) 27%, transparent 27%,
    transparent 52%, rgba(255, 255, 255, .4) 52%,
    rgba(255, 255, 255, .4) 77%, transparent 77%,
    transparent
  );
  background-image: linear-gradient(
    135deg,
    rgba(255, 255, 255, .4) 27%, transparent 27%,
    transparent 52%, rgba(255, 255, 255, .4) 52%,
    rgba(255, 255, 255, .4) 77%, transparent 77%,
    transparent
  );
}

.markdown-body .progress-100plus .progress-bar {
  background-color: #a6d796;
}

.markdown-body .progress-80plus .progress-bar {
  background-color: #c6d796;
}

.markdown-body .progress-60plus .progress-bar {
  background-color: #d7c896;
}

.markdown-body .progress-40plus .progress-bar {
  background-color: #d7a796;
}

.markdown-body .progress-20plus .progress-bar {
  background-color: #d796a6;
}

.markdown-body .progress-0plus .progress-bar {
  background-color: #c25f77;
}

.markdown-body .candystripe-animate .progress-bar{
  -webkit-animation: animate-stripes 3s linear infinite;
  -moz-animation: animate-stripes 3s linear infinite;
  animation: animate-stripes 3s linear infinite;
}

@-webkit-keyframes animate-stripes {
  0% {
    background-position: 0 0;
  }

  100% {
    background-position: 60px 0;
  }
}

@-moz-keyframes animate-stripes {
  0% {
    background-position: 0 0;
  }

  100% {
    background-position: 60px 0;
  }
}

@keyframes animate-stripes {
  0% {
    background-position: 0 0;
  }

  100% {
    background-position: 60px 0;
  }
}

.markdown-body .gloss .progress-bar {
  box-shadow:
    inset 0 4px 12px rgba(255, 255, 255, .7),
    inset 0 -12px 0 rgba(0, 0, 0, .05);
}

/* Multimarkdown Critic Blocks */
.markdown-body .critic_mark {
  background: #ff0;
}

.markdown-body .critic_delete {
  color: #c82829;
  text-decoration: line-through;
}

.markdown-body .critic_insert {
  color: #718c00 ;
  text-decoration: underline;
}

.markdown-body .critic_comment {
  color: #8e908c;
  font-style: italic;
}

.markdown-body .headeranchor {
  font: normal normal 16px fontawesome-mini;
  line-height: 1;
  display: inline-block;
  text-decoration: none;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}

.headeranchor:before {
  content: '\e157';
}

.markdown-body .task-list-item {
  list-style-type: none;
}

.markdown-body .task-list-item+.task-list-item {
  margin-top: 3px;
}

.markdown-body .task-list-item input {
  margin: 0 4px 0.25em -20px;
  vertical-align: middle;
}

/* Media */
@media only screen and (min-width: 480px) {
  .markdown-body {
    font-size:14px;
  }
}

@media only screen and (min-width: 768px) {
  .markdown-body {
    font-size:16px;
  }
}

@media print {
  .markdown-body * {
    background: transparent !important;
    color: black !important;
    filter:none !important;
    -ms-filter: none !important;
  }

  .markdown-body {
    font-size:12pt;
    max-width:100%;
    outline:none;
    border: 0;
  }

  .markdown-body a,
  .markdown-body a:visited {
    text-decoration: underline;
  }

  .markdown-body .headeranchor-link {
    display: none;
  }

  .markdown-body a[href]:after {
    content: " (" attr(href) ")";
  }

  .markdown-body abbr[title]:after {
    content: " (" attr(title) ")";
  }

  .markdown-body .ir a:after,
  .markdown-body a[href^="javascript:"]:after,
  .markdown-body a[href^="#"]:after {
    content: "";
  }

  .markdown-body pre {
    white-space: pre;
    white-space: pre-wrap;
    word-wrap: break-word;
  }

  .markdown-body pre,
  .markdown-body blockquote {
    border: 1px solid #999;
    padding-right: 1em;
    page-break-inside: avoid;
  }

  .markdown-body .progress,
  .markdown-body .progress-bar {
    -moz-box-shadow: none;
    -webkit-box-shadow: none;
    box-shadow: none;
  }

  .markdown-body .progress {
    border: 1px solid #ddd;
  }

  .markdown-body .progress-bar {
    height: 22px;
    border-right: 1px solid #ddd;
  }

  .markdown-body tr,
  .markdown-body img {
    page-break-inside: avoid;
  }

  .markdown-body img {
    max-width: 100% !important;
  }

  .markdown-body p,
  .markdown-body h2,
  .markdown-body h3 {
    orphans: 3;
    widows: 3;
  }

  .markdown-body h2,
  .markdown-body h3 {
    page-break-after: avoid;
  }
}
</style><style>/*github*/
.codehilite {background-color:#fff;color:#333333;}
.codehilite .hll {background-color:#ffffcc;}
.codehilite .c{color:#999988;font-style:italic}
.codehilite .err{color:#a61717;background-color:#e3d2d2}
.codehilite .k{font-weight:bold}
.codehilite .o{font-weight:bold}
.codehilite .cm{color:#999988;font-style:italic}
.codehilite .cp{color:#999999;font-weight:bold}
.codehilite .c1{color:#999988;font-style:italic}
.codehilite .cs{color:#999999;font-weight:bold;font-style:italic}
.codehilite .gd{color:#000000;background-color:#ffdddd}
.codehilite .ge{font-style:italic}
.codehilite .gr{color:#aa0000}
.codehilite .gh{color:#999999}
.codehilite .gi{color:#000000;background-color:#ddffdd}
.codehilite .go{color:#888888}
.codehilite .gp{color:#555555}
.codehilite .gs{font-weight:bold}
.codehilite .gu{color:#800080;font-weight:bold}
.codehilite .gt{color:#aa0000}
.codehilite .kc{font-weight:bold}
.codehilite .kd{font-weight:bold}
.codehilite .kn{font-weight:bold}
.codehilite .kp{font-weight:bold}
.codehilite .kr{font-weight:bold}
.codehilite .kt{color:#445588;font-weight:bold}
.codehilite .m{color:#009999}
.codehilite .s{color:#dd1144}
.codehilite .n{color:#333333}
.codehilite .na{color:teal}
.codehilite .nb{color:#0086b3}
.codehilite .nc{color:#445588;font-weight:bold}
.codehilite .no{color:teal}
.codehilite .ni{color:purple}
.codehilite .ne{color:#990000;font-weight:bold}
.codehilite .nf{color:#990000;font-weight:bold}
.codehilite .nn{color:#555555}
.codehilite .nt{color:navy}
.codehilite .nv{color:teal}
.codehilite .ow{font-weight:bold}
.codehilite .w{color:#bbbbbb}
.codehilite .mf{color:#009999}
.codehilite .mh{color:#009999}
.codehilite .mi{color:#009999}
.codehilite .mo{color:#009999}
.codehilite .sb{color:#dd1144}
.codehilite .sc{color:#dd1144}
.codehilite .sd{color:#dd1144}
.codehilite .s2{color:#dd1144}
.codehilite .se{color:#dd1144}
.codehilite .sh{color:#dd1144}
.codehilite .si{color:#dd1144}
.codehilite .sx{color:#dd1144}
.codehilite .sr{color:#009926}
.codehilite .s1{color:#dd1144}
.codehilite .ss{color:#990073}
.codehilite .bp{color:#999999}
.codehilite .vc{color:teal}
.codehilite .vg{color:teal}
.codehilite .vi{color:teal}
.codehilite .il{color:#009999}
.codehilite .gc{color:#999;background-color:#EAF2F5}
</style><title>AJAX</title></head><body><article class="markdown-body"><div class="toc">
<ul>
<li><a href="#ajax">Ajax</a><ul>
<li><a href="#ajax_1">了解AJAX</a></li>
<li><a href="#ajax_2">AJAX请求步骤</a></li>
<li><a href="#xmlhttprequest">XMLHttpRequest对象属性方法</a><ul>
<li><a href="#xmlhttprequest_1">XMLHttpRequest的兼容性（了解）</a></li>
</ul>
</li>
<li><a href="#json">JSON数据的应用</a></li>
<li><a href="#ajax_3">ajax跨域解决方案</a><ul>
<li><a href="#jsonp">JSONP</a><ul>
<li><a href="#jsonp_1">jsonp请求原理</a></li>
</ul>
</li>
<li><a href="#cors">CORS</a></li>
<li><a href="#_1">服务器代理</a></li>
</ul>
</li>
<li><a href="#promise">Promise</a><ul>
<li><a href="#promise_1">Promise 的三种状态</a></li>
<li><a href="#_2">方法</a><ul>
<li><a href="#_3">静态方法</a></li>
<li><a href="#_4">原型方法</a></li>
</ul>
</li>
<li><a href="#_5">使用</a></li>
<li><a href="#_6">应用</a></li>
</ul>
</li>
<li><a href="#api">API</a></li>
</ul>
</li>
</ul>
</div>
<h1 id="ajax">Ajax<a class="headerlink" href="#ajax" title="Permanent link"></a></h1>
<h2 id="ajax_1">了解AJAX<a class="headerlink" href="#ajax_1" title="Permanent link"></a></h2>
<ul>
<li>AJAX: Asynchronous Javascript And Xml，Ajax 技术的核心是XMLHttpRequest对象（简称XHR），这是由微软首先引入的一个特性，其他浏览器提供商后来都提供了相同的实现</li>
</ul>
<p>*Ajax起源：
最早出现在2005年的google搜索建议</p>
<ul>
<li>
<p>ajax优点</p>
<ul>
<li>增加速度：减轻服务器的负担,按需加载数据,最大程度的减少冗余请求</li>
<li>改善的用户体验：局部刷新页面,减少用户等待时间,带来更好的用户体验</li>
<li>页面和数据分离：前后端分离，操作更灵活，后期维护更方便</li>
</ul>
</li>
<li>
<p>后端语言和服务器配置</p>
<ul>
<li>php + Apache + mySQL</li>
<li>NodeJS + MongoDB</li>
<li>Java + tomcat + Oracle</li>
<li>.NET + IIS + SQL Server</li>
</ul>
</li>
</ul>
<h2 id="ajax_2">AJAX请求步骤<a class="headerlink" href="#ajax_2" title="Permanent link"></a></h2>
<ol>
<li>
<p>创建请求对象,返回一个异步请求对象
<code>var xhr = new XMLHttpRequest();</code></p>
</li>
<li>
<p>处理服务器返回数据
<div class="codehilite"><pre><span class="nx">xhr</span><span class="p">.</span><span class="nx">onreadystatechange</span> <span class="o">=</span> <span class="kd">function</span><span class="p">(){</span>
    <span class="k">if</span><span class="p">(</span><span class="nx">xhr</span><span class="p">.</span><span class="nx">readyState</span> <span class="o">==</span> <span class="mi">4</span><span class="p">)</span> <span class="p">{</span>
        <span class="nx">alert</span><span class="p">(</span><span class="nx">xhr</span><span class="p">.</span><span class="nx">responseText</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</pre></div></p>
</li>
<li>
<p>设置请求参数，建立与服务器连接
<code>xhr.open("get", "http://localhost/api/ajaxtest", true);</code></p>
</li>
<li>
<p>向服务器发送请求
<code>xhr.send(null);</code></p>
</li>
</ol>
<h2 id="xmlhttprequest">XMLHttpRequest对象属性方法<a class="headerlink" href="#xmlhttprequest" title="Permanent link"></a></h2>
<ul>
<li>
<p>open(type,url,async): 建立与服务器的连接</p>
<ul>
<li>type：请求的类型 （get, post, put, delete&hellip;）</li>
<li>
<p>url：数据请求的地址（API地址），一般由后端开发人员提供</p>
<ul>
<li>当前页面访问地址，API地址两者一定要<strong>同域</strong></li>
<li>同域：协议，域名，端口三者一致（同源策略）</li>
</ul>
</li>
<li>
<p>async：是否异步发送请求（true,false），默认为true</p>
<ul>
<li>同步：按步骤顺序执行，前面的代码执行完后，后面的代码才会执行<blockquote>
<p>做完前一件事情, 才能下一件事情（排队）</p>
</blockquote>
</li>
<li>异步：与其他操作同时执行，也叫并发（图片加载，ajax请求）</li>
</ul>
</li>
</ul>
</li>
<li>
<p>send(data): 向服务器发送请求</p>
<ul>
<li>
<p>data：可选参数，post请求时才生效，表示发请求时传送的数据字符串。
<div class="codehilite"><pre>    <span class="nx">xhr</span><span class="p">.</span><span class="nx">send</span><span class="p">(</span><span class="s1">&#39;size=20&amp;type=music&#39;</span><span class="p">);</span>
</pre></div></p>
<blockquote>
<p>在某些浏览器中，如果不需要通过请求主体发送数据，则必须传入null</p>
</blockquote>
</li>
<li>
<p>get请求的数据写在api地址后
<div class="codehilite"><pre>    request.open(&quot;get&quot;, &quot;http://localhost/api/getdata.php?type=get&amp;qty=10&quot;, true);
</pre></div></p>
</li>
</ul>
</li>
<li>
<p>setRequestHeader(key,val)：设置请求头</p>
<ul>
<li>设置请求头必须在open方法调用后设置<blockquote>
<p>利用请求头设置POST提交数据格式：
xhr.setRequestHeader(&lsquo;content-type&rsquo;,&rdquo;application/x-www-form-urlencoded&rdquo;);</p>
</blockquote>
</li>
</ul>
</li>
</ul>
<blockquote>
<p>**在请求收到服务器的响应后，响应的数据会自动填充xhr 对象的属性，相关的属性简介如下：</p>
</blockquote>
<ul>
<li>readyState<ul>
<li>0 － （未初始化）尚未调用open()方法。</li>
<li>1 － （启动）已经调用open()方法，但尚未调用send()方法。</li>
<li>2 － （发送）send()方法执行完成，但尚未接收到响应。</li>
<li>3 － （接收）已经接收到部分响应数据。</li>
<li>4 － （完成）响应内容解析完成，可以在客户端调用了</li>
</ul>
</li>
</ul>
<blockquote>
<p>只要readyState 属性的值由一个值变成另一个值，都会触发一次readystatechange 事件。必须在调用open()之前指定onreadystatechange事件处理程序才能确保跨浏览器兼容性。</p>
</blockquote>
<ul>
<li>responseText：保存服务器返回的数据（从服务器返回的数据是“字符串”）。</li>
<li>status：响应的HTTP 状态。<ul>
<li>200（OK）：服务器成功返回了页面</li>
<li>304（Not Modified）：数据与服务器相同，不需要重服务器请求（直接使用缓存的数据）</li>
<li>400（Bad Request）：语法错误导致服务器不识别</li>
<li>401（Unauthorized）：请求需要用户认证</li>
<li>404（Not found）：请求地址不存在</li>
<li>500（Internal Server Error）：服务器出错或无响应</li>
<li>503（ServiceUnavailable）：由于服务器过载或维护导致无法完成请求</li>
</ul>
</li>
<li>statusText: HTTP状态码的说明</li>
</ul>
<h3 id="xmlhttprequest_1">XMLHttpRequest的兼容性（了解）<a class="headerlink" href="#xmlhttprequest_1" title="Permanent link"></a></h3>
<div class="codehilite"><pre><span class="kd">var</span> <span class="nx">req</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="k">try</span><span class="p">{</span>
    <span class="nx">req</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">XMLHttpRequest</span><span class="p">();</span>
<span class="p">}</span><span class="k">catch</span><span class="p">(</span><span class="nx">err</span><span class="p">){</span>
    <span class="c1">// ie低版本浏览有多种异步请求的实现</span>
    <span class="k">try</span><span class="p">{</span>
        <span class="nx">req</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">ActiveXObject</span><span class="p">(</span><span class="s2">&quot;Msxml2.XMLHTTP&quot;</span><span class="p">);</span>
    <span class="p">}</span><span class="k">catch</span><span class="p">(</span><span class="nx">err</span><span class="p">){</span>
        <span class="k">try</span><span class="p">{</span>
            <span class="nx">req</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">ActiveXObject</span><span class="p">(</span><span class="s2">&quot;Microsoft.XMLHTTP&quot;</span><span class="p">);</span>
        <span class="p">}</span><span class="k">catch</span><span class="p">(</span><span class="nx">err</span><span class="p">){</span>
            <span class="nx">alert</span><span class="p">(</span><span class="s1">&#39;你的浏览器太low了，这个世界不适合你&#39;</span><span class="p">);</span>
        <span class="p">}</span>
    <span class="p">}</span>

<span class="p">}</span>
</pre></div>

<h2 id="json">JSON数据的应用<a class="headerlink" href="#json" title="Permanent link"></a></h2>
<ul>
<li>
<p>xml数据（了解）
<div class="codehilite"><pre><span class="nt">&lt;person&gt;</span>
    <span class="nt">&lt;id&gt;</span>4564523626256562<span class="nt">&lt;/id&gt;</span>
    <span class="nt">&lt;name&gt;</span>张三<span class="nt">&lt;/name&gt;</span>
<span class="nt">&lt;/person&gt;</span>
</pre></div></p>
</li>
<li>
<p>json数据(json字符串)
<div class="codehilite"><pre>    <span class="p">{</span><span class="s2">&quot;id&quot;</span> <span class="o">:</span> <span class="mi">21465461461461</span><span class="p">,</span> <span class="s2">&quot;name&quot;</span><span class="o">:</span> <span class="s2">&quot;张三&quot;</span><span class="p">},[{</span><span class="s2">&quot;id&quot;</span> <span class="o">:</span> <span class="mi">21465461461461</span><span class="p">,</span> <span class="s2">&quot;name&quot;</span><span class="o">:</span> <span class="s2">&quot;张三&quot;</span><span class="p">}]</span>
</pre></div></p>
<ul>
<li>json数据格式要求</li>
<li>json字符串的转换<ul>
<li>eval方法转换
<code>eval("("+json字符串+")");</code> 
它的作用是，将一个普通的json格式的字符串，转换成Json格式的对象
举例：
<div class="codehilite"><pre>    <span class="kd">var</span> <span class="nx">list</span> <span class="o">=</span> <span class="nb">eval</span><span class="p">(</span><span class="s2">&quot;(&quot;</span><span class="o">+</span><span class="nx">request</span><span class="p">.</span><span class="nx">responseText</span><span class="o">+</span><span class="s2">&quot;)&quot;</span><span class="p">);</span>
</pre></div></li>
<li>JSON对象(ES5)<ul>
<li>JSON.parse(); //把JSON字符串转成JSON对象(js对象/数组)</li>
<li>JSON.stringify(); //把JSON对象转成JSON字符串</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>
<p>加载json文件
前后端分离开发时模拟数据</p>
</li>
</ul>
<h2 id="ajax_3">ajax跨域解决方案<a class="headerlink" href="#ajax_3" title="Permanent link"></a></h2>
<h3 id="jsonp">JSONP<a class="headerlink" href="#jsonp" title="Permanent link"></a></h3>
<p>JSONP 是JSON with padding（填充式JSON 或参数式JSON）的简写。
JSONP是一种可以绕过浏览器的安全限制，从不同的域请求数据的方法。使用JSONP需要服务器端提供必要的支持。
<div class="codehilite"><pre><span class="x">callback({ &quot;name&quot;: &quot;Nicholas&quot; });//此代码在服务器生成</span>
</pre></div></p>
<blockquote>
<p>JSONP 由两部分组成：回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数</p>
</blockquote>
<h4 id="jsonp_1">jsonp请求原理<a class="headerlink" href="#jsonp_1" title="Permanent link"></a></h4>
<ul>
<li>
<p>JSONP的原理是通过script标签发起一个GET请求来取代XHR请求。</p>
<ul>
<li>JSONP生成一个script标签并插到DOM中，</li>
<li>然后浏览器会接管并向src属性所指向的地址发送请求。</li>
<li>从服务器端返回一段js代码，这段代码就是一个函数的执行（执行时把数据作为参数传入，函数为本地预定义的函数）,这个我们就间接地得到了服务器传出的数据。</li>
</ul>
</li>
<li>
<p>步骤如下：</p>
<ol>
<li>
<p>预定义全局函数getData
<div class="codehilite"><pre><span class="kd">function</span> <span class="nx">getData</span><span class="p">(</span><span class="nx">data</span><span class="p">){</span>
    <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
<span class="p">}</span>
</pre></div></p>
<blockquote>
<p>PS:预定义函数必须为全局函数</p>
</blockquote>
</li>
<li>
<p>生成script标签，请求服务器地址,并附带函数名
<div class="codehilite"><pre>&lt;script src=&quot;http://localhost:3000/getJSONP?callback=getData&quot;&gt;&lt; /script&gt;
</pre></div></p>
</li>
<li>服务器返回js文件（js文件里面包含我们预先定义的函数执行）
请求成功后，得到的js代码为
<div class="codehilite"><pre><span class="nx">getData</span><span class="p">({</span><span class="nx">name</span><span class="o">:</span> <span class="s1">&#39;王大锤&#39;</span><span class="p">,</span><span class="nx">age</span><span class="o">:</span> <span class="mi">30</span><span class="p">,</span><span class="nx">sex</span><span class="o">:</span> <span class="s1">&#39;男&#39;</span><span class="p">,</span><span class="nx">married</span><span class="o">:</span><span class="kc">false</span><span class="p">})</span>
</pre></div>
当这个函数成功调用时，就可以执行预定义函数里的代码（处理返回的数据）</li>
</ol>
</li>
</ul>
<blockquote>
<p>jsonp请求不是ajax请求，是利用script标签能加载其他域名的js文件的原理，来实现跨域数据的请求</p>
</blockquote>
<ul>
<li>缺点
这种方法只支持GET方式，不如POST方式安全</li>
</ul>
<h3 id="cors">CORS<a class="headerlink" href="#cors" title="Permanent link"></a></h3>
<p>CORS是一个W3C标准，全称是&rdquo;跨域资源共享&rdquo;（Cross-origin resource sharing），它允许浏览器向跨源服务器发出XMLHttpRequest请求，从而克服了AJAX只能同源使用的限制</p>
<blockquote>
<p>CORS需要浏览器和服务器同时支持。目前，所有浏览器都支持该功能，IE浏览器不能低于IE10。</p>
</blockquote>
<ul>
<li>Access-Control-Allow-Origin
该字段是必须的。需要在后端响应头添加词字段，值要么是一个*，表示接受任意域名的请求，要么指定一个域名<code>http://localhost</code>,如想指定若干个请使用判断语句，php代码如下
<div class="codehilite"><pre><span class="x">    $origin = $_SERVER[&#39;HTTP_ORIGIN&#39;];</span>

<span class="x">    $allow_origin = array(  </span>
<span class="x">        &#39;http://www.client.com&#39;,  </span>
<span class="x">        &#39;http://www.client2.com&#39;  </span>
<span class="x">    );  </span>

<span class="x">    if(in_array($origin, $allow_origin)){  </span>
<span class="x">        header(&#39;Access-Control-Allow-Origin:&#39;.$origin);  </span>
<span class="x">    }  </span>
</pre></div></li>
<li>Access-Control-Allow-Methods</li>
<li>Access-Control-Allow-Headers
<div class="codehilite"><pre><span class="x">    header(&#39;Access-Control-Allow-Methods:POST&#39;);  </span>
<span class="x">    header(&#39;Access-Control-Allow-Headers:x-requested-with,content-type&#39;); </span>
</pre></div></li>
</ul>
<h3 id="_1">服务器代理<a class="headerlink" href="#_1" title="Permanent link"></a></h3>
<p>后端不存在跨域问题，所以可以利用后端间接获取其他网站的数据</p>
<h2 id="promise">Promise<a class="headerlink" href="#promise" title="Permanent link"></a></h2>
<p>Promise是一个构造函数，所谓的Promise对象，就是通过new Promise()实例化得到的对象，用来传递异步操作的消息。它代表了某个未来才会知道结果的事件（通常是一个异步操作），并且这个事件提供统一的 API，可供进一步处理。</p>
<h3 id="promise_1">Promise 的三种状态<a class="headerlink" href="#promise_1" title="Permanent link"></a></h3>
<ul>
<li>Pending（未完成）可以理解为Promise对象实例创建时候的初始状态</li>
<li>Resolved（成功） 可以理解为成功的状态</li>
<li>Rejected（失败） 可以理解为失败的状态</li>
</ul>
<h3 id="_2">方法<a class="headerlink" href="#_2" title="Permanent link"></a></h3>
<h4 id="_3">静态方法<a class="headerlink" href="#_3" title="Permanent link"></a></h4>
<ul>
<li><code>Promise.resolve()</code>
将现有对象转为Promise对象，并将该对象的状态改成resolved
<div class="codehilite"><pre><span class="kd">var</span> <span class="nx">p</span> <span class="o">=</span> <span class="nx">Promise</span><span class="p">.</span><span class="nx">resolve</span><span class="p">(</span><span class="s1">&#39;foo&#39;</span><span class="p">);</span>

<span class="c1">// 等价于</span>
<span class="kd">var</span> <span class="nx">p</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Promise</span><span class="p">(</span><span class="nx">resolve</span> <span class="o">=&gt;</span> <span class="nx">resolve</span><span class="p">(</span><span class="s1">&#39;foo&#39;</span><span class="p">));</span>
</pre></div></li>
<li><code>Promise.reject()</code>
返回一个新的 Promise 实例，该实例的状态为rejected</li>
<li><code>Promise.all([p1,p2,p3...])</code> 
将多个Promise实例，包装成一个新的Promise实例<ul>
<li>所有参数中的promise状态都为resolved是，新的promise状态才为resolved</li>
<li>只要p1、p2、p3..之中有一个被rejected，新的promise的状态就变成rejected</li>
</ul>
</li>
<li><code>Promise.race([p1,p2,p3...])</code> // 竞速，完成一个即可</li>
</ul>
<h4 id="_4">原型方法<a class="headerlink" href="#_4" title="Permanent link"></a></h4>
<ul>
<li><code>Promise.prototype.then(successFn[,failFn])</code>
Promise实例生成以后，可以用then方法分别指定Resolved状态和Rejected状态的回调函数。并根据Promise对象的状态来确定执行的操作:<ul>
<li>resolved时执行第一个函数successFn</li>
<li>rejected时执行第二个函数failFn。</li>
</ul>
</li>
<li><code>Promise.prototype.catch(failFn)</code></li>
</ul>
<h3 id="_5">使用<a class="headerlink" href="#_5" title="Permanent link"></a></h3>
<p><div class="codehilite"><pre>    <span class="kd">var</span> <span class="nx">p</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Promise</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">resolve</span><span class="p">,</span> <span class="nx">reject</span><span class="p">){</span>
        <span class="c1">//ajax请求</span>
        <span class="nx">ajax</span><span class="p">({</span>
            <span class="nx">url</span><span class="o">:</span><span class="s1">&#39;xxx.php&#39;</span><span class="p">,</span>
            <span class="nx">success</span><span class="o">:</span><span class="kd">function</span><span class="p">(</span><span class="nx">data</span><span class="p">){</span>
                <span class="nx">resolve</span><span class="p">(</span><span class="nx">data</span><span class="p">)</span>
            <span class="p">},</span>
            <span class="nx">fail</span><span class="o">:</span><span class="kd">function</span><span class="p">(){</span>
                <span class="nx">reject</span><span class="p">(</span><span class="s1">&#39;请求失败&#39;</span><span class="p">)</span>
            <span class="p">}</span>
        <span class="p">});</span>
    <span class="p">});</span>

    <span class="c1">//指定Resolved状态和Rejected状态的回调函数</span>
    <span class="c1">//一般用于处理数据</span>
    <span class="nx">p</span><span class="p">.</span><span class="nx">then</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">res</span><span class="p">){</span>
        <span class="c1">//这里得到resolve传过来的数据</span>
    <span class="p">},</span><span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">){</span>
        <span class="c1">//这里得到reject传过来的数据</span>
    <span class="p">})</span>
</pre></div>
Promise的构造函数接收一个回调函数作为参数，并且传入两个参数：resolve，reject，分别表示异步操作执行成功和失败后的回调函数</p>
<ul>
<li>调用resolve方法将Promise对象的状态从「未完成」变为「成功」（从 pending 变为 resolved）；</li>
<li>调用reject方法将Promise对象的状态从「未完成」变为「失败」（从 pending 变为 rejected）</li>
<li>如果调用resolve函数和reject函数时带有参数，那么它们的参数会被传递给回调函数</li>
</ul>
<blockquote>
<p>有了Promise对象，就可以将异步操作以同步操作的流程表达出来，避免了层层嵌套的回调函数</p>
</blockquote>
<h3 id="_6">应用<a class="headerlink" href="#_6" title="Permanent link"></a></h3>
<ul>
<li>加载图片，获取图片信息（宽高）
<div class="codehilite"><pre>    <span class="kd">var</span> <span class="nx">preloadImage</span> <span class="o">=</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">path</span><span class="p">)</span> <span class="p">{</span>
      <span class="k">return</span> <span class="k">new</span> <span class="nx">Promise</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">resolve</span><span class="p">,</span> <span class="nx">reject</span><span class="p">)</span> <span class="p">{</span>
        <span class="kd">var</span> <span class="nx">image</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">Image</span><span class="p">();</span>
        <span class="nx">image</span><span class="p">.</span><span class="nx">onload</span>  <span class="o">=</span> <span class="p">()</span><span class="o">=&gt;</span><span class="p">{</span>
            <span class="nx">resolve</span><span class="p">(</span><span class="nx">image</span><span class="p">);</span>
        <span class="p">}</span>
        <span class="nx">image</span><span class="p">.</span><span class="nx">onerror</span> <span class="o">=</span> <span class="nx">reject</span><span class="p">;</span>
        <span class="nx">image</span><span class="p">.</span><span class="nx">src</span> <span class="o">=</span> <span class="nx">path</span><span class="p">;</span>
      <span class="p">});</span>
    <span class="p">};</span>

    <span class="c1">//使用</span>
    <span class="nx">preloadImage</span><span class="p">(</span><span class="s1">&#39;http://image.baidu.com/xxx.jpg&#39;</span><span class="p">).</span><span class="nx">then</span><span class="p">((</span><span class="nx">img</span><span class="p">)</span><span class="o">=&gt;</span><span class="p">{</span>
        <span class="nb">document</span><span class="p">.</span><span class="nx">body</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">img</span><span class="p">);</span>
        <span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="nx">img</span><span class="p">.</span><span class="nx">offsetWidth</span><span class="p">,</span><span class="nx">img</span><span class="p">.</span><span class="nx">offsetHeight</span><span class="p">);</span>
    <span class="p">})</span>
</pre></div></li>
<li>多个ajax请求数据依赖</li>
</ul>
<h2 id="api">API<a class="headerlink" href="#api" title="Permanent link"></a></h2>
<ul>
<li>
<p>本地服务器API</p>
<ul>
<li>
<p>判断用户名是否已被注册</p>
<ul>
<li>接口地址：api/checkname.php</li>
<li>接口描述：验证所提交的用户名是否存在<ul>
<li>已存在（不可注册）：返回no</li>
<li>不存在（可注册）：返回yes</li>
</ul>
</li>
<li>参数说明：<ul>
<li>regname:注册用户名（必填）<blockquote>
<p>已经存在的名字：&rsquo;laoxie&rsquo;,&rsquo;lemon&rsquo;,&rsquo;王尼玛&rsquo;,&rsquo;奥巴马&rsquo;</p>
</blockquote>
</li>
</ul>
</li>
</ul>
</li>
<li>
<p>微博消息</p>
<ul>
<li>获取：<ul>
<li>接口地址：api/weibo.php</li>
<li>接口描述：返回包含多条微博记录的json数据</li>
</ul>
</li>
<li>点赞：<ul>
<li>接口地址：api/weibo.php</li>
<li>接口描述：点赞数量+1</li>
<li>参数说明：<ul>
<li>id: 消息对应id（必填）</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>
<p>分页获取数据：</p>
<ul>
<li>接口地址：api/football.php    </li>
<li>接口描述：根据分页和每页数量请求多条微博信息的数据</li>
<li>参数说明：<ul>
<li>pageNo:当前分页，默认1</li>
<li>qty:每页显示数量，默认10</li>
</ul>
</li>
</ul>
</li>
<li>
<p>聊天室：</p>
<ul>
<li>接口地址：api/chat.php</li>
<li>接口描述：聊天室的发送与信息获取</li>
<li>参数说明：<ul>
<li>type<ul>
<li>query: 获取聊天消息</li>
<li>send: 发送信息</li>
</ul>
</li>
<li>sender: 发送信息用户名</li>
<li>msg: 信息内容</li>
</ul>
</li>
</ul>
</li>
<li>
<p>利用jsonp获取远程数据</p>
<ul>
<li>接口地址：api/jsonp.php</li>
<li>接口描述：jsonp跨域解决方案</li>
</ul>
</li>
<li>
<p>获取CORS获取远程数据</p>
<ul>
<li>接口地址：api/cors.php</li>
<li>接口描述：CORS跨域解决方案</li>
</ul>
</li>
<li>
<p>获取ip地址</p>
<ul>
<li>本机内网ip地址：api/inner_ip.php</li>
<li>利用服务器代理获取外网ip:api/outer_ip.php</li>
</ul>
</li>
</ul>
</li>
<li>
<p>跨域api</p>
<ul>
<li>
<p>利用jsonp实现百度搜索关键字建议
    <code>https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?json=1&amp;cb=getData&amp;wd=html5</code></p>
</li>
<li>
<p>利用CORS加载天气
    接口地址：<code>http://wthrcdn.etouch.cn/weather_mini?city=北京</code>
    接口描述：通过城市名字获得天气数据，json数据</p>
</li>
<li>
<p>利用服务器代理根据ip获取城市</p>
<ul>
<li>根据IP获取所在城市
<code>http://ip.taobao.com/service/getIpInfo.php?ip=61.144.96.228</code></li>
</ul>
</li>
</ul>
</li>
</ul>
<hr />
<p>【案例】</p>
<ol>
<li>滚动页面加载更（懒加载）</li>
<li>封装ajax函数，要求如下：<ul>
<li>简化ajax请求操作</li>
<li>解决兼容性问题</li>
<li>支持跨域JSONP请求</li>
</ul>
</li>
</ol>
<p><strong>【作业】</strong></p>
<ol>
<li>ajax请求json数据实现实现城市列表的展示<ul>
<li>显示热门城市</li>
<li>支持字母索引</li>
<li>点击城市显示相应天气信息
<img alt="Alt text" src="///F://mydoc/kphone/h5/Section2/Outline3/content/23-24Ajax/doc/img/1.png" title="Optional title" /></li>
</ul>
</li>
</ol>
<p><strong>【扩展】</strong></p>
<ul>
<li>全国地市三级联动效果
<img alt="Alt text" src="///F://mydoc/kphone/h5/Section2/Outline3/content/23-24Ajax/doc/img/2.png" title="Optional title" /></li>
</ul></article></body></html>